/**
 * @(#)CoordinadorBundlesTraductor.java 6/06/2010
 *
 * Copyright (c) 2007-2012 PsiqueWare S.A. de C.V. All Rights Reserved.
 * This software is the proprietary information PsiqueWare S.A. de C.V.
 * Use is subject to license terms.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *
 * <br/>Usuario : AngelElectrico
 * <br/>Creaci&oacute;n: 6/06/2010 - 10:59:16 AM
 * <br/>
 * <br/>
 * <br/><t5>Cambios :</t5>
 * <br/><b>Fecha | Autor  |  Cambios</b>
 * <ul>
 * <li>6/06/2010 | <a href = "mailto:AngelElectrico@PsiqueWare.com">&Aacute;ngel El&eacute;ctrico</a> | Creaci&oacute;n del Objeto.</li>
 *
 * </ul>
 */

package com.psiqueware.alheli.i18n.traductor;

import com.psiqueware.alheli.exception.NullArgumentException;
import com.psiqueware.alheli.i18n.CoordinadorBundles;
import com.psiqueware.alheli.i18n.Traductor;
import com.psiqueware.alheli.i18n.osgi.CoordinadorBundlesOsgi;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.ResourceBundle;

/**
 * {@link CoordinadorBundles} con la capacidad de realizar una traducci&oacute;n de los elementos utilizando un traductor.
 * <br/>Paquete Original: com.psiqueware.alheli.i18n.traductor
 * <br/>Nombre  Original: CoordinadorBundlesTraductor
 * <br/>Oprima para ver : <a href="CoordinadorBundlesTraductor.java.html"><i>C&oacute;digo Fuente</i> </a>
 *
 * @author <a href="mailto:AngelElectrico@PsiqueWare.com">AngelElectrico</a>
 * @version Revision: 1.1 6/06/2010 10:59:16 AM
 */
public final class CoordinadorBundlesTraductor implements CoordinadorBundles
{

    /**
     * Nombres de los Bundles.
     */
    private final Map<String, ContextoBundleTraductor> m_contextos = new HashMap<String, ContextoBundleTraductor>();

    /**
     * {@link CoordinadorBundles} de donde se obtendr&aacute;n los valores iniciales.
     */
    private final CoordinadorBundles m_coordinadorBundles;

    /**
     * Directorio donde se almacenar&aacute;n las traducciones.
     */
    private final File m_directorioTraducciones;

    /**
     * {@link Locale} origen de la traduci&oacute;n.
     */
    private Locale m_localeOrigen = Locale.ENGLISH;

    /**
     * {@link Traductor} para los nuevos bundles.
     */
    private final Traductor m_traductor;

    /**
     * Constructor de CoordinadorBundlesTraductor.
     *
     * @param traductor              a utilizar.
     * @param coordinadorBundles     {@link CoordinadorBundles} de donde se obtendr&aacute;n los valores iniciales.
     * @param directorioTraducciones Directorio donde se almacenar&aacute;n las traducciones.
     */
    public CoordinadorBundlesTraductor(final Traductor traductor, final CoordinadorBundles coordinadorBundles, final File directorioTraducciones)
    {
        m_traductor = traductor;
        m_coordinadorBundles = coordinadorBundles;
        m_directorioTraducciones = directorioTraducciones;
    }

    /**
     * Agrega un {@link ResourceBundle} a la colecci&oacute;n coordinada.
     *
     * @param contexto    en esta implementaci&oacute;n no se utiliza.
     * @param baseName    nombre base del bundle.
     * @param classLoader a cargar.
     */
    private void agregarResourceBundle(final String contexto, final String baseName, ClassLoader classLoader)
    {
        if (null == baseName)
            throw new NullArgumentException("<error>El argumento 'baseName' no puede ser NULL.</error>");
        if (null == classLoader) classLoader = Thread.currentThread().getContextClassLoader();

        synchronized (m_contextos)
        {
            ContextoBundleTraductor contextoBundle = m_contextos.get(contexto);
            if (null == contextoBundle)
            {
                contextoBundle = new ContextoBundleTraductor(contexto, m_directorioTraducciones);
                m_contextos.put(contexto, contextoBundle);
            }
            if (!contextoBundle.containsClassLoader(classLoader)) contextoBundle.addClassLoader(classLoader);
            if (!contextoBundle.containsClassLoader(CoordinadorBundlesOsgi.class.getClassLoader()))
                contextoBundle.addClassLoader(CoordinadorBundlesOsgi.class.getClassLoader());
            if (!contextoBundle.containsBaseNames(baseName)) contextoBundle.addBaseName(baseName);
        }
    }

    /**
     * Agrega un {@link ResourceBundle} a la colecci&oacute;n coordinada.
     *
     * @param contexto en el que se definir&aacute; el Bundle.
     * @param baseName nombre base del bundle.
     */
    public void agregarResourceBundle(final String contexto, final String baseName)
    {
        agregarResourceBundle(contexto, baseName, baseName.getClass().getClassLoader());
        m_coordinadorBundles.agregarResourceBundle(contexto, baseName);
    }

    /**
     * Agrega un {@link ResourceBundle} a la colecci&oacute;n coordinada.
     *
     * @param contexto      en el que se definir&aacute; el Bundle.
     * @param classBaseName nombre base del bundle.
     */
    public void agregarResourceBundle(final String contexto, final Class classBaseName)
    {
        agregarResourceBundle(contexto, classBaseName.getName(), classBaseName.getClassLoader());
        m_coordinadorBundles.agregarResourceBundle(contexto, classBaseName);
    }

    /**
     * Agrega un {@link ResourceBundle} a la colecci&oacute;n coordinada.
     *
     * @param baseName nombre base del bundle.
     */
    public void agregarResourceBundle(final String baseName)
    {
        agregarResourceBundle("", baseName, baseName.getClass().getClassLoader());
        m_coordinadorBundles.agregarResourceBundle(baseName);
    }

    /**
     * Agrega un {@link ResourceBundle} a la colecci&oacute;n coordinada.
     *
     * @param classBaseName nombre base del bundle.
     */
    public void agregarResourceBundle(final Class classBaseName)
    {
        agregarResourceBundle("", classBaseName.getName(), classBaseName.getClassLoader());
        m_coordinadorBundles.agregarResourceBundle(classBaseName);
    }

    /**
     * Agrega un {@link ResourceBundle} a la colecci&oacute;n coordinada y lo devuelve.
     *
     * @param contexto en el que se definir&aacute; el Bundle.
     * @param baseName nombre base del bundle.
     *
     * @return {@link ResourceBundle} buscado.
     */
    public ResourceBundle agregaBuscaResourceBundle(String contexto, String baseName, Locale locale)
    {
        agregarResourceBundle(contexto, baseName, locale.getClass().getClassLoader());
        m_coordinadorBundles.agregarResourceBundle(contexto, baseName);
        return getBundle(locale, contexto);
    }

    /**
     * Agrega un {@link ResourceBundle} a la colecci&oacute;n coordinada y lo devuelve.
     *
     * @param contexto      en el que se definir&aacute; el Bundle.
     * @param classBaseName nombre base del bundle.
     *
     * @return {@link ResourceBundle} buscado.
     */
    public ResourceBundle agregaBuscaResourceBundle(String contexto, Class classBaseName, Locale locale)
    {
        agregarResourceBundle(contexto, classBaseName.getName(), classBaseName.getClassLoader());
        m_coordinadorBundles.agregarResourceBundle(contexto, classBaseName);
        return getBundle(locale, contexto);
    }

    /**
     * Agrega un {@link ResourceBundle} a la colecci&oacute;n coordinada y lo devuelve.
     *
     * @param classBaseName nombre base del bundle.
     * @param locale        {@link Locale} del bundle buscado.
     *
     * @return {@link ResourceBundle} buscado.
     */
    public ResourceBundle agregaBuscaResourceBundle(final Class classBaseName, final Locale locale)
    {
        m_coordinadorBundles.agregarResourceBundle(classBaseName);
        return agregaBuscaResourceBundle("", classBaseName, locale);
    }

    /**
     * Agrega un {@link ResourceBundle} a la colecci&oacute;n coordinada y lo devuelve.
     *
     * @param baseName nombre base del bundle.
     *
     * @return {@link ResourceBundle} buscado.
     */
    public ResourceBundle agregaBuscaResourceBundle(final String baseName)
    {
        m_coordinadorBundles.agregarResourceBundle(baseName);
        return agregaBuscaResourceBundle("", baseName, Locale.getDefault());
    }

    /**
     * Agrega un {@link ResourceBundle} a la colecci&oacute;n coordinada y lo devuelve.
     *
     * @param classBaseName nombre base del bundle.
     *
     * @return {@link ResourceBundle} buscado.
     */
    public ResourceBundle agregaBuscaResourceBundle(final Class classBaseName)
    {
        m_coordinadorBundles.agregarResourceBundle(classBaseName);
        return agregaBuscaResourceBundle("", classBaseName, Locale.getDefault());
    }

    /**
     * Devuelve un ResourceBundle para un {@link Locale} sin tomar en cuenta el contexto.
     *
     * @param locale   localidad cuyos recursos se buscan.
     * @param contexto para el Bundle. No se utiliza pero cumple con el contrato de la interfaze.
     *
     * @return {@link ResourceBundle}.
     */
    public ResourceBundle getBundle(final Locale locale, final String contexto)
    {
        final ContextoBundleTraductor contextoBundle = m_contextos.get(contexto);
        try
        {
            final ResourceBundle rbOrigen = m_coordinadorBundles.getBundle(m_localeOrigen, contexto);
            return contextoBundle.getBundle(rbOrigen, m_traductor, m_localeOrigen, locale);
        }
        catch (IOException e)
        {
            final String error = "<error><msg>No se pudo salvar la descarga.</msg><parametros>" + contextoBundle.getFile(locale) + "</parametros></error>";
            System.err.println(error);
            System.err.println(e);
            throw new RuntimeException(error, e);
        }

    }

    /**
     * Devuelve un ResourceBundle para el {@link Locale} sin importarle el contexto de los recursos.
     *
     * @param locale localidad cuyos recursos se buscan.
     *
     * @return {@link ResourceBundle}.
     */
    public ResourceBundle getBundle(Locale locale)
    {
        return getBundle(locale, "");
    }

    /**
     * Devuelve un ResourceBundle sin importarle el contexto de los recursos y utilizando el {@link Locale} por defecto.
     *
     * @return {@link ResourceBundle}.
     */
    public ResourceBundle getBundle()
    {
        return getBundle(Locale.getDefault(), "");
    }
}

